package cn.kgc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.kgc.entity.Menus;
import cn.kgc.entity.MetaVo;
import cn.kgc.entity.RolesMenus;
import cn.kgc.entity.RouterVo;
import cn.kgc.mapper.MenusMapper;
import cn.kgc.service.MenusService;
import cn.kgc.service.RolesMenusService;
import cn.kgc.util.SystemUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static cn.kgc.util.SystemConstant.MENU_TYPE_BUTTON;


/**
 * @author YC
 */
@Slf4j
@Service("menusService")
public class MenusServiceImpl extends ServiceImpl<MenusMapper, Menus> implements MenusService {

    @Resource
    private RolesMenusService rolesMenusService;

    @Override
    public List<Menus> selectAllMenusByRoleId(Integer roleId) {
        // 查询角色的菜单
        List<RolesMenus> rolesMenus =
                rolesMenusService.list(new LambdaQueryWrapper<RolesMenus>().eq(RolesMenus::getRid, roleId));
        List<Menus> menus = rolesMenus.stream()
                .map(roleMenu -> getById(roleMenu.getMid())).collect(Collectors.toList());
        // 排除父级菜单
        List<Menus> tempMenus = CollUtil.newArrayList(menus);
        menus.forEach(menu -> {
            tempMenus.removeIf(tempMenu -> tempMenu.getId().equals(menu.getParentId()));
        });
        return tempMenus;
    }

    @Override
    public List<SimpleGrantedAuthority> getAuthoritiesByUserId(Integer userId) {
        // 获得角色拥有的菜单集合
        List<Menus> menus = selectAllMenusByRoleId(userId);
        // 处理出权限集合（过滤出权限菜单，转换为权限对象，收集集合）
        return menus.stream()
                .filter(menu -> menu.getMenuType() == MENU_TYPE_BUTTON)
                .map(menu -> new SimpleGrantedAuthority(menu.getPerm()))
                .collect(Collectors.toList());
    }

    @Override
    public List<String> getMenuPerms() {
        Integer roleId = SystemUtil.getLoginUser().getRoleId();
        List<Menus> menus = selectAllMenusByRoleId(roleId);
        return menus.stream()
                .filter(menu -> menu.getMenuType() == MENU_TYPE_BUTTON)
                .map(Menus::getPerm)
                .collect(Collectors.toList());
    }

    @Override
    public List<RouterVo> getRouterVoList() {
        Integer roleId = SystemUtil.getLoginUser().getRoleId();
        LambdaQueryWrapper<RolesMenus> wrapper =
                new LambdaQueryWrapper<RolesMenus>().eq(RolesMenus::getRid, roleId);
        List<RolesMenus> list = rolesMenusService.list(wrapper);
        if (CollUtil.isEmpty(list)) {
            return List.of();
        }
        List<Integer> menusIds = list.stream()
                .map(RolesMenus::getMid)
                .collect(Collectors.toList());
        List<Menus> menus = this.listByIds(menusIds);
        if (CollUtil.isEmpty(menus)) {
            return List.of();
        }
        List<Menus> menusList = SystemUtil.tree(menus);
        return generateRouterVoList(menusList);
    }

    private List<RouterVo> generateRouterVoList(List<Menus> menus) {
        List<RouterVo> routerVoList = new ArrayList<>();
        for (Menus menu : menus) {
            RouterVo routerVo = new RouterVo();
            // 如果菜单类型是按钮，需要判断组件是否为空
            if (menu.getMenuType() == MENU_TYPE_BUTTON) {
                // 组件不为空不需要转为路由信息，继续循环
                if (StrUtil.isBlank(menu.getComponent())) {
                    continue;
                }
                // 组件为空需要转为路由信息且需要在菜单上隐藏（有些按钮是需要跳转页面的）
                routerVo.setHide(true);
            }
            // 将菜单的信息保存到路由中
            BeanUtil.copyProperties(menu, routerVo);
            routerVo.setName(menu.getMenuName());
            routerVo.setMeta(new MetaVo(menu.getMenuName()));
            // 判断当前菜单/按钮是否有子菜单
            if (CollUtil.isNotEmpty(menu.getChildren())) {
                // 递归调用
                List<RouterVo> routerVos = generateRouterVoList(menu.getChildren());
                routerVo.setChildren(routerVos);
            }
            routerVoList.add(routerVo);
        }
        return routerVoList;
    }

}
